# Copyright 2001-2007 by iNeed,Inc. All Rights Reserved.
#-*- encoding:utf-8 -*-
"""
key:
s: stop
g: goto
m: moveto
=: speed up
-: slowdown
p: publish short term request
o: publish long tern request

"""


from config import *
from common import *
import gameEngine
import database
import driver,passenger
import gridManager
__author__  = "Number Huang<huang.bafeng@iNeed.com>"
__status__  = "developing"
__version__ = "0.1108.31.1"
FPS=20
SPEED=30
AUTOEXE=False #auto execute order when pickup time is near
MAP_WIDTH=1280
MAP_HEIGHT=640
"""
top middle:                         31.255789576586757     121.44171237945556
right： 31.235261199614772  121.48887634277344
bottom:      31.215150439316506  121.45817041397095
"""
globalFlag = 0
right= 12148887.634
top  = 3125578.957
latitude_scale =6.35
longtidue_scale=7.36
def getLocation2(y,x):
    latitude    = int(top-y*latitude_scale)
    longtidue   = int(right-(MAP_WIDTH-x)*longtidue_scale)
    return (latitude,longtidue,u"mockMapStreet")

def reverseGetLocation(latitude,longtidue):
    if (globalFlag&TEST_WITH_WEB):
        y = int((top - latitude)/latitude_scale)
        x = MAP_WIDTH-int((right - longtidue)/longtidue_scale)
        return (x,y)
    else:
        return (longtidue,latitude)

def isTestWithWeb():
    return globalFlag&TEST_WITH_WEB

def map2Real(address):
    latitude,longtidue = getLocation2(address[1],address[0])[:2]
    return (latitude,longtidue,address[2])

MAX_FRAME_CHANGE = 63

log1 = gameEngine.log1


CTSR2_ARRIVE     = "arrive"
CTSR2_ONGOING    = "ongoing"


NotifyDlgList =[ESE_WF_GUI_CO,ESE_WF_GUI_CA,ESE_WF_GUI_CD,ESE_WF_GUI_TOGD]
NotifyMenuList=["LOGIN",CSTR_GPS]

#flag to control the game
RUN_SERVER = 1
NOTIFY_ALL = 2
TEST_WITH_WEB = 4
if False:
    FilterRequestList=[CSTR_CO,CSTR_CA,CSTR_CD,CSTR_BT,CSTR_ET] #just for test,because the most clip issue on pygame
else:
    FilterRequestList=[CSTR_BT,CSTR_ET,CSTR_RB] #just for test,because the most clip issue on pygame
class ConfirmEvent(object):
    def __init__(self,method,info,extraInfo,reporter):
        self.method = method
        self.info   = info
        self.extraInfo = extraInfo
        self.reporter = reporter
        
class Entity(gameEngine.SuperSprite):
    def __init__(self,name,scene,img,initPos,endPos):

      gameEngine.SuperSprite.__init__(self, name,scene,initPos)
      self.setImage(os.path.join(IMGPath,img))
      self.initPos = initPos
      self.endPos = endPos
      self.change  = 0
      self.request = None
      self.destination=[0,0]
      self.activeOrder = None
      self.infoDlg = gameEngine.PopupMenu("infoDlg",self.scene)
      self.confirmDlg = gameEngine.PopupMenu("confirmDlg",self.scene,pos=(MAP_WIDTH/2,MAP_HEIGHT/2),size=(480,480))
      self.onTransaction = False
      #self.waitForConfirm = False
      self.clock = pygame.time.Clock() 
      self.showStatus = False
    def OnKeyDown(self,event):
        if event.key ==pygame.K_l:
                self.showStatus = True #self.TestPos()     
          
    def exit(self):
        if(globalFlag&TEST_WITH_WEB):
            return
        
        if self.peer:
            self.peer.exit()

    def login(self):
        try:
          reporter = DialogReporter(self,"LOGIN")
        
          self.peer.logIn(self.phone,"fdd",centerID,centerAddr,reporter)
        except:
          self._ShowInfo("LOGIN","login fail,may be the server is not available")
          self.log.exception("login fail")


    def _randomWalk(self):
        #random go
        
        if self.change==0:
            self.x,self.y = self.initPos
            self.setDX(0.3)
        elif (self.change&MAX_FRAME_CHANGE)==0:
            dx = random.random()
            self.setDX(dx)
            dy = 1 - dx
            if dy<0.2:
                dy = -dy
            if dx>0.5:
                self.speedUp(dx)
            self.setDY(dy)

        self.change += 1
   
    def handleFilterRequest(self,method,info,extraInfo,reporter):   
            pass
        
    def handleRequest(self,method,info,extraInfoDict,reporter):
        
        
        event = ConfirmEvent(method,info,extraInfoDict,reporter)
        #self.eventList.append(my_event)
        #pygame.event.post(my_event)
        #if event.type == EVT_WAITCONFIRM[0]:
        #   self.log.debug("event property:%s"%str(paramDict))
        method = event.method
        if notifyGUITable.has_key(method):
             if method in FilterRequestList:#this is only for test
                   if reporter:
                       reporter.notify(EN_OK,retCodeMap[EN_OK]) 
                   self.handleFilterRequest(method,info,extraInfoDict,reporter) 
             else:#to notify the user to act
                    self.request = event
                        #self.waitForConfirm = True
    
        
    def checkEvents(self):
        try:
            if True:
                time_passed         = self.clock.tick(FPS)     
                time_passed_seconds = time_passed / 1000.0
                if self.speed:
                    self.speed = SPEED*time_passed_seconds
                #self.log.debug("speed=%f,timepassed=%f"%(self.speed,time_passed_seconds))
            while self.eventList:
                event = self.eventList.pop()
                if event.type == MOUSEBUTTONDOWN:
                        self.OnClick(event)
                elif event.type==KEYDOWN:
                        self.OnKeyDown(event)
            if self.request:
                self.setSpeed(0)
                self.rotateBy(10)                                              
            else:
                self.checkMoreStatus()#for the subClass to process more status
            
            if  self.showStatus:
                self.TestPos()  
        except:
            self.log.exception("fail2")   
    def confirm(self,method,pubID):        
        self.request = None
        
        if method==CSTR_CD and self.peer.role==EPR_DRIVER: #execute order directly
            if self.activeOrder and self.activeOrder.poolingProcessor:#pooling
                order = self.peer.queryService(pubID)
                self.executePoolingOrder(order)#
                
    def OnClick(self,event):

        if event.buttons[2]==1:#right click
            self._ShowDialog()

        elif event.buttons[0]==1 and self.request:#left click

            method = self.request.method
            if notifyGUITable.has_key(method):
              
                self.request.reporter.notify(EN_OK,retCodeMap[EN_OK])#(EN_CANCEL,retCodeMap[EN_CANCEL])   
                self.request = None
                  
    def _ShowInfo(self,method,info):

     
        self.infoDlg.addInfo(method+"\r\n"+info)
        self.scene.addOneSprite(self.infoDlg)
    
    def TestPos(self):
        
        pos1 = self.rect.center[1],self.rect.center[0]
        pos2 = getLocation2(pos1[0],pos1[1])[:2]
        gm = gridManager.gridManagerFactory()
        if isTestWithWeb():
            row,col = gm.getTheGrid(pos2[0],pos2[1]).getRowCol()
        else:
            row,col = gm.getTheGrid(pos1[0],pos1[1]).getRowCol()
        #self.infoDlg2.addInfo("pos=(%d,%d)\nlatlng=(%d,%d)\ngrid(%d,%d)\n"%(pos1[0],pos1[1],pos2[0],pos2[1],row,col))
        #self.scene.addOneSprite(self.infoDlg2) 
        posInfo = "%d:pos=(%d,%d)\nlatlng=(%d,%d)\ngrid(%d,%d)\n"%(configall.getTimeIdx(),pos1[0],pos1[1],pos2[0],pos2[1],row,col)
        
        if self.activeOrder:
             statusInfo=FSMTable[self.activeOrder.status][2]
        else:
             statusInfo=FSMTable[self.peer.status][2] 
        
        if self.peer.role==EPR_DRIVER:
            name = driverNameDict[self.peer.phoneNum]
            isOffer = True
        else:
            name = passengerNameDict[self.peer.phoneNum]
            isOffer = False
        info = posInfo + statusInfo
        info2 = "\n"
        infoList2= gm.getDumpInfoByID(self.peer.phoneNum,isOffer)
        if infoList2:
            for item in infoList2:
                info2 += item +"\n"
        self._ShowInfo(self.peer.phoneNum+"-%s"%name,info+info2)    
        
    def _HideInfo(self):
        self.scene.deleteOneSprite(self.infoDlg)
        
    def _ShowDialog(self):

        if self.request:
            method = self.request.method
            if notifyGUITable.has_key(method):
                self.confirmDlg.setName("%sDlg"%method)
                self.confirmDlg.addOneDialog(method+"\r\n"+str(self.request.info),self.OnClickOKBun,self.OnClickCancelBun)
                self.scene.addOneSprite(self.confirmDlg)
   
    def _driveToDestination(self,dest,speed=1):
        dir= self.dirTo(dest)
        self.setAngle(dir)
        self.setSpeed(speed) 
         
    def OnClickOKBun(self,param=None):

        if self.request:#it is possible that click more than one time
            method = self.request.method
            self.log.debug("ok click_%s"%method)
            
                
            #if method==CSTR_CO or method==CSTR_TOGD:
             #   paramDict[CSTR3_REPORTER]=DialogReporter(self,method)
            if self.request.reporter:
                self.request.reporter.notify(EN_OK,retCodeMap[EN_OK])  
            
            self.request = None



    def OnClickCancelBun(self,param=None):

        if self.request:#it is possible that click more than one time
            method = self.request.method
            self.log.debug("cancel click%s"%method)
            if self.request.reporter:
                self.request.reporter.notify(EN_CANCEL,retCodeMap[EN_CANCEL])  
            self.request = None

    

    def getLocation(self,lat=None,longt=None):
        gm = gridManager.gridManagerFactory()
        if not lat:
            lat   = self.rect.centery
            longt = self.rect.centerx
        grid = gm.getTheGrid(lat,longt).getRowCol()
        fakeLocation = u"grid %s"%str(grid)
        if True:#globalFlag&TEST_WITH_WEB:
            return (lat,longt,fakeLocation)
        else:
            return (self.rect.centerx,self.rect.centery,fakeLocation)
        
    def getLocation2(self,lat=None,longt=None):
        if not lat:
            lat   = self.rect.centery
            longt = self.rect.centerx
        return getLocation2(lat,longt)
    
MAX_TAXI_NUM=9
MAX_PASSENGER_NUM=8

        
class Taxi(Entity):
    def __init__(self,phone,scene,img,initPos,endPos):
      self.phone = phone
      name = "driver%s"%phone
      super(Taxi,self).__init__(name,scene,img,initPos,endPos)

      #self.requestHandler[CSTR_BT]=self.handleBT
      
      self.excutingCount = 0
      self.log = getLogger("iNeed.%s"%name,os.path.join(DRIVER_LOG_PATH,"%s.txt"%name))
      self.showOrderList = False
      self.poolingOrder = None
      self.speed = 1
      self.log.debug("initpos=(%d,%d)"%self.initPos)
      
    def getNextDest(self):
        return tuple(self.destination)
    
    def getSpeed(self):
        return self.speed
    
    def setNextDest(self,dest):
            dest = reverseGetLocation(dest[0],dest[1])
            if tuple(self.destination)!=dest:
                self.log.debug("new dest(%d,%d)"%dest)
                self.destination=list(dest)
    
    def updatePooling(self,info="unknown"): 
        #self.log.debug("updatePooling by %s"%info)
        self.activeOrder.poolingProcessor.update()
        self.activeOrder = self.activeOrder.poolingProcessor.getActiveOrder() 
        if self.activeOrder and self.activeOrder.status == ESE_ORDER_DONE:
            self.peer.executeOrder(self.activeOrder)
          
    def updatePoolingNGo(self): 
        if self.activeOrder:
            self.updatePooling()
            destination = self.activeOrder.getNextDest()
            if self.getNextDest()!=destination:
                self.setNextDest(destination)
                self._driveToDestination(self.getNextDest())
              
    def executePoolingOrder(self,order):
        self.activeOrder = order
        self.peer.executeOrder(order)
        self.updatePooling("executePoolingOrder")
        d1 = self.activeOrder.getNextDest()
        self.setNextDest(d1)
        self._driveToDestination(self.getNextDest())
            
    def executeOrder(self,order):
       
        if order.status==ESE_ORDER_DONE:
            
            
            self.activeOrder = order
            
            #self.destination[0] = self.activeOrder.orderDict['x2']
            #self.destination[1] = self.activeOrder.orderDict['y2']
            #destination = (self.activeOrder.orderDict['x'],self.activeOrder.orderDict['y'])
            
            #self._ShowInfo("GOFOR_PICKUP",passengerNameDict[order.orderDict["passengerID"]])
            
            self.beginT = False
            if self.activeOrder.poolingProcessor:
                self.updatePooling("executeOrder")
            else:
                self.peer.executeOrder(self.activeOrder)
            destination = self.activeOrder.getNextDest()
            self.setNextDest(destination)
            self._driveToDestination(self.getNextDest())
            
    def checkMoreStatus(self):
       
       if self.activeOrder:
           
           if self.activeOrder.status == ESE_GOFOR_PICKUP:
               
                self.hasArrived = False
                self.beginT = False
                destination = reverseGetLocation(self.activeOrder.orderDict['x'],self.activeOrder.orderDict['y'])
                if self.rect.collidepoint(destination):
                    self.activeOrder.updateStatus(ESE_READY_PICKUP)
                    self.setSpeed(0)#stop
                    self.peer.notifyBording(self.activeOrder.orderDict["passengerID"])
                self._driveToDestination(self.getNextDest())
                #if self.activeOrder.poolingProcessor:#this may change the dest and activeOrder
                #    self.updatePoolingNGo()   
           elif self.activeOrder.status == ESE_TRANSATION_GOING: 
               
               if not self.speed:
                   self.speed = 1  
                   
               if self.activeOrder.poolingProcessor:#this may change the dest and activeOrder
                   self.updatePoolingNGo()
                   
               if self.activeOrder.status==ESE_TRANSATION_GOING:#the active order and dest may change by updatePoolingNGo()       
                   if not self.beginT:# and self.activeOrder.status==ESE_TRANSATION_GOING: #if :#the active order may change by updatePoolingNGo
                        self.beginT = True
                        self.handleBT()
                        self.peer.beginTransaction(self.activeOrder.pubID)
               
                 
                   if self.rect.collidepoint(self.destination):
                        #self.activeOrder.updateStatus(ESE_READY_ET)
                        if not (globalFlag&TEST_WITH_WEB):
                            #self.peer.endTransaction(self.activeOrder.pubID)
                            self.activeOrder.updateStatus(ESE_TRANSATION_DONE)
                        self.speed = 0
              
                    
               #self._driveToDestination(self.getNextDest(),self.speed)
                         
           elif self.activeOrder.status == ESE_TRANSATION_DONE:
                    #self.activeOrder.updateStatus(ESS_CLOSED)
                    curOrderID = self.activeOrder.pubID
                    if not (globalFlag&TEST_WITH_WEB):
                        self.peer.endTransaction(curOrderID)
                    self.beginT = False
                    if self.activeOrder.poolingProcessor:
                        self.updatePooling("TRANSATION_DONE")
                        self._ShowInfo("TRANSATION_DONE","go on picking up next")
                    else:
                        self.activeOrder = None
                        self._ShowInfo("TRANSATION_DONE","You can try next order")
                        
                    if self.activeOrder:
                        """
                        if self.activeOrder.status == ESE_TRANSATION_GOING:
                           destination = (self.activeOrder.orderDict['x2'],self.activeOrder.orderDict['y2'])
                        else:#impossible
                           destination = (self.activeOrder.orderDict['x'],self.activeOrder.orderDict['y'])
                           self._driveToDestination(destination)
                        """
                        
                        destination = self.activeOrder.getNextDest()
                        self.setNextDest(destination)
                        self._driveToDestination(self.getNextDest())
                  
       elif AUTOEXE:
                self.executeOrder2()
       
       if self.peer.status == ES_IDLE:
                    #self._randomWalk()
                    self.setSpeed(0)
                    self.onTransaction = False
       
       
       
   
    def OnKeyDown(self,event):
        if event.key ==pygame.K_e:
            self.executeOrder2()
        else:
            Entity.OnKeyDown(self, event) 
    
    def executeOrder2(self): 
        for service in self.peer.serviceList:
            if service.status==ESE_ORDER_DONE and service.orderDict["departureTime"]-time.time()<5:
                """
                if service.poolingProcessor:#pooling
                
                    self.executePoolingOrder(service)#
                else:
                """
                self.log.debug("executing order")
                self.executeOrder(service)
                break
                                        
    def OnClick(self,event):
        if event.buttons[2]==1 and not self.request:
            
            if self.showOrderList:
                self._ShowDriverMenu()
        else:
            if self.request and self.request.method==CSTR_CA:
                readyExe = 1
            else:
                readyExe = 0
           
            Entity.OnClick(self,event)
            if readyExe: #and notifyGUITable.has_key(method):
                self.executeOrder2()
    def calculateNextDest(self,status):
        pass
    
    def handleBT(self):
        dest = (self.activeOrder.orderDict['x2'],self.activeOrder.orderDict['y2'])
           
        self.setNextDest(dest)    
        self._driveToDestination(self.getNextDest())
         
    def handleFilterRequest(self,method,info,extraInfo,reporter):   
        if method==CSTR_BT:
             self.handleBT()
             
    def OnClickOKBun(self,param=None):
        
        if self.request: 
            method = self.request.method
            id = self.request.extraInfo[CSTR2_PUBID]
            Entity.OnClickOKBun(self,param)
            if method==CSTR_CD and not self.showOrderList: #execute order directly
                order = self.peer.queryService(id)
                if self.activeOrder and order.orderDict["poolingID"]==self.activeOrder.pubID:#pooling
                    self.executePoolingOrder(order)#
                else:
                    self.executeOrder(order)
            
    def _ShowDriverMenu(self):
        
        orderlist = self.peer.queryServiceByStatus(ESE_ORDER_DONE)
        if orderlist:
            menu = gameEngine.PopupMenu("orderListMenu",self.scene)
            menu.addOneItem("order list")
            for order in orderlist:
                #orderDict = order.orderDict
                paramDict = {CSTR3_SERVICE:order}
                menu.addOneItem(str(order.pubID),self.executeOrder,paramDict)
            self.scene.addOneSprite(menu)
        
class Person(Entity):

    def __init__(self,phone,scene,img,initPos,endPos):

      self.phone=phone
      name = "Passenger%s"%phone
      super(Person,self).__init__(name,scene,img,initPos,endPos)
      self.menu = gameEngine.PopupMenu("addServiceMenu",self.scene)
      self.menu.addOneItem("Get One Taxi",self.Publish)
      #self.requestHandler[CSTR_UDS] = self.handleUDS
      #self.requestHandler[CSTR_TOGD] = self.handleTOGD
      self.driverPos={}
      self.log = getLogger("iNeed.%s"%name,os.path.join(PASSENGER_LOG_PATH,"%s.txt"%name))
      self._reset()
      self.infoDlg2 = gameEngine.PopupMenu("posDlg",self.scene,pos=(640,120))
      self.showpeerPos = True
      self.posMenu = gameEngine.PopupMenu("posMenu",self.scene)
      self.posMenu.addOneItem("Show driver Pos",self.ShowPeerPos)
      self.driver = None
      self.log.debug("initpos=(%d,%d)"%self.initPos[:2])
      self.log.debug("endpos=(%d,%d)"%(self.endPos[0],self.endPos[1]))
      self.activeDest = None
      
    def _reset(self):
        self.beginTansaction = False
        self.activeOrder=None
        self.posCounter = 0
        self.driver = None
        
    def checkMoreStatus(self):

       if self.peer.status == ES_IDLE:
           pass#self.stop()
       elif self.activeOrder:
           if self.activeOrder.status == ESE_TRANSATION_GOING:
               if not self.driver:
                   self.driver = self.scene.getPeerByID(self.activeOrder.orderDict["driverID"])
               dest = self.driver.getNextDest()
               self._driveToDestination(dest,self.driver.getSpeed())
               
                 
               if self.distanceTo(reverseGetLocation(self.destination[0],self.destination[1]))<self.rect.width and self.driver.getSpeed()==0:#self.rect.collidepoint(self.destination):
                    if globalFlag&TEST_WITH_WEB:
                        self.activeOrder.updateStatus(ESE_READY_ET)
                    else:
                        params={"score":2,"comment":"not bad game"}
                        self.peer.comment(self.activeOrder,params)
                        #self._driveToDestination(self.initPos[:2])
                    self.speed = 0
               else:
                    pass #self.TestPos()
           if self.activeOrder.status == ESE_TRANSATION_DONE:
                
                #self.activeOrder.updateStatus(ESS_CLOSED)
                self._reset()
                self.speed = 0
               
           elif self.activeOrder.status==ESE_ORDER_DONE:
               
                if False:#(self.posCounter&7)==0 and self.showpeerPos and not (globalFlag&TEST_WITH_WEB):
                    self.getPeerPosition(self.activeOrder.orderDict["driverID"]) 
                    if self.driverPos.has_key('x'):
                        info = "(%d,%d,%s)\r\n"%(self.driverPos['x'],self.driverPos['y'],self.driverPos['address'])
                        info += "distance:%d\r\n"%self.driverPos['distance']
                        #self._ShowInfo(CSTR_GPS,info)
                        self.infoDlg2.addInfo(CSTR_GPS+"\r\n"+info)
                        #self.scene.addOneSprite(self.infoDlg2)
                self.posCounter += 1
                self.destination[0] = self.activeOrder.orderDict['x2']
                self.destination[1] = self.activeOrder.orderDict['y2']
           """     
           elif self.activeOrder.status==ESE_READY_BORDING and not (globalFlag&TEST_WITH_WEB):
                 if self.driverPos.has_key('x'):
                     pos = (self.driverPos['x'],self.driverPos['y'])
                     dir= self.dirTo(pos)
                     self.setAngle(dir)
                     self.setSpeed(1)
        
                     if   self.beginTansaction==False and self.rect.collidepoint(pos):
        
                            self.setSpeed(0)
                            self.beginTansaction = True
                            #reporter = DialogReporter(self,CSTR_BT)
                            #self.activeOrder.updateStatus(ESE_WFR_BT)
                            
                            self.driverPos.clear()
                            self.scene._removePopUpMenu()
            """


    def OnKeyDown(self,event):
        
        numDict={pygame.K_0:"0",
                 pygame.K_1:"1",
                 pygame.K_2:"2",
                 pygame.K_3:"3",
                 pygame.K_4:"4",
                 pygame.K_5:"5",
                 pygame.K_6:"6",
                 pygame.K_7:"7",
                 pygame.K_8:"8",
                 pygame.K_9:"9"}
        
        if event.key in numDict.keys():
            time1 = configall.SHORTTIME_LIMIT
            mod = pygame.key.get_mods() 
            if mod&pygame.KMOD_LCTRL:#publish enable pooling
               isPooling = EST_BOOKING
            else:
               isPooling = EST_POOLING
            idx = int(numDict[event.key])
            time1 = time1*idx   
            
            self.Publish2(time1,isPooling)
        elif event.key==pygame.K_u:
            self.unpublish()
        else:
            Entity.OnKeyDown(self, event)   
   
    def OnClick(self,event):
        if event.buttons[2]==1:
            if self.peer.status ==ES_IDLE:
                return self._ShowPassengerMenu()
            #elif self.activeOrder and self.activeOrder.status ==ESE_ORDER_DONE:#right click
            #    return self._ShowPosMenu()
        
        Entity.OnClick(self,event)
    
    
    def _ShowPassengerMenu(self,paramDict=None):
        self.scene.addOneSprite(self.menu)

    def _ShowPosMenu(self,paramDict=None):
        self.scene.addOneSprite(self.posMenu)
        
    def ShowPeerPos(self,param):
        
        self.showpeerPos = not self.showpeerPos
   
   
    def Publish(self,param):
        paramsDict={}
        paramsDict["departureLocation"] = (self.initPos[1],self.initPos[0],self.initPos[2])
        paramsDict["departureTime"] = (time.time() + 900)
        paramsDict["type"]  = EST_BPEITHER
        paramsDict["timeout"] = BASELINE_TIMEOUT*3 #this is used for test
        paramsDict["destinationLocation"] = (self.endPos[1],self.endPos[0],self.endPos[2])
        #paramsDict["destinationTime"] = None
        #paramsDict["price"] = None
        paramsDict["number"] = 1
        try:
            reporter = DialogReporter(self,"PUBLISH")
            self.activeOrder = self.peer.addService(reporter,paramsDict)
        except Exception,e:
            self.log.exception("publish fail\nreason: %s"%e)
        
        self.destination[0] = self.endPos[0]
        self.destination[1] = self.endPos[1]     
        self.driverPos.clear()
        self.peer.updateStatus(ES_BUSY) #TODO: this is only for test
        self.setSpeed(0)
        
    def Publish2(self,departTime,type):
        paramsDict={}
        paramsDict["departureLocation"] = self.getLocation() #(self.initPos[1],self.initPos[0],self.initPos[2])
        paramsDict["departureTime"] = (time.time() + departTime)
        paramsDict["type"]  = type
        paramsDict["timeout"] = 900#BASELINE_TIMEOUT*3 #this is used for test
        if not self.activeDest:
            self.activeDest=(1000,600)
        paramsDict["destinationLocation"] = self.getLocation(self.activeDest[1],self.activeDest[0])
        #paramsDict["destinationTime"] = None
        #paramsDict["price"] = None
        paramsDict["number"] = 2
        try:
            reporter = DialogReporter(self,"PUBLISH")
            self.activeOrder = self.peer.addService(reporter,paramsDict)
        except Exception,e:
            self.log.exception("publish fail\nreason: %s"%e)
        
        #self.destination[0] = self.activeDest[0]
        #self.destination[1] = self.activeDest[1]    
        self.driverPos.clear()
        self.peer.updateStatus(ES_BUSY) #TODO: this is only for test
        self.setSpeed(0)
    
    def unpublish(self):
        
        if self.peer.serviceList:
            order = self.peer.serviceList.pop()
            self.peer.deleteService(None, order)     
            
    def handleGPSResponse(self,retCode,retInfo,extraInfo):
        
        if self.activeOrder.status==ESE_ORDER_DONE and not (globalFlag&TEST_WITH_WEB):
            if extraInfo.has_key(CSTR2_GPS):
                strlist = extraInfo[CSTR2_GPS].splitlines()
                for line1 in strlist:
                    if line1.startswith("Location:"):
                            y,x,address = getLocation(line1)
                            self.driverPos["x"] = x
                            self.driverPos["y"] = y
                            self.driverPos["address"] = address
                            self.driverPos['distance'] = self.distanceTo((x,y))
        
                            #if self.driverPos['distance']<self.rect.width :
                            #    self.activeOrder.updateStatus(ESE_READY_BORDING)
        

    def getPeerPosition(self,phone):
        if  not (globalFlag&TEST_WITH_WEB):
            reporter = Reporter(None,self.handleGPSResponse)
            self.peer.getPeerPos(phone,reporter)



class DialogReporter(Reporter):

    def __init__(self,owner,requestName,errorFunc=None,okFunc=None,timeout=10,async=True):
        super(DialogReporter,self).__init__(None,None,timeout,async)

        self.request   = requestName
        self.errorFunc = errorFunc
        self.okFunc = okFunc
        self.owner = owner
    def notify(self,retCode,retInfo,extraInfo=None):

        if retCode>=300:
            okFunc = self.errorFunc
            #self.owner.changeStatus(FSMTable[self.owner.status][1])
        else:
            okFunc = self.okFunc
            #self.owner.changeStatus(FSMTable[self.owner.status][0])

        if (retCode>=300) or (self.okFunc and retCode<300):
            self.dlg = gameEngine.PopupMenu("DialogReporter",self.owner.scene)
            self.dlg.addOneDialog("%s:%d %s"%(self.request,retCode,retInfo),okFunc)
            self.owner.scene.addOneSprite(self.dlg)
initPos=(
         [(202,72,u"上海西站"),(210,148,u"万里城"),(503,182,u"普陀公园"),(600,300,u"古井假日酒店"),(360,360,u"金沙江路地铁站"),(140,320,u"未知"),(140,320,u"未知"),(140,320,u"未知"),(140,320,u"未知"),(140,320,u"未知")],#passenger
         [(60,60),(160,60),(260,60),(360,60),(460,60),(560,60),(60,160),(60,260),(860,60),(960,60)] #driver
)
endPos=(
         [(987,162,u"交通公园"),(870,111,u"上海火车站"),(812,132,u"龙门宾馆"),(1000,480,u"大世界"),(1000,480,u"大世界"),(1000,480,u"大世界"),(1000,480,u"大世界"),(1000,480,u"大世界"),(1000,480,u"大世界"),(1000,480,u"大世界")],#passenger
         [] #driver
)
passengerNameList=["wolf","bear","sheep","mouse","pig","taishan","tiger","shitSheep"]
passengerNameDict={}
driverNameList=["black","white","green","red","blue","yellow","cyan"]
driverNameDict={}
class IneedMap(gameEngine.Scene):
    """
        class comment
    """

    def __init__(self,size=(640,480),img=None):
        super(IneedMap,self).__init__(size,img)
        self.taxiList=[]
        self.personList=[]
        menu = gameEngine.PopupMenu("addMenu",self)
        menu.addOneItem("Add taxi",self.addOneTaxi)
        menu.addOneItem("Add passenger",self.addOnePerson)
        self.addPeerMenu = menu
        self.addList=[]
        self.deleteList=[]
        self.db = database.CreateDB()
        self.driverList     = self._getUserList(True)
        self.passengerList  = self._getUserList(False)
        cleanDataBaseForTest(self.db)
        
    def _getUserList(self,isDriver):
        result = self.db.fetchall("driver",None)
        driverList=[]
        for idx,row in enumerate(result):
            driverList.append([row[-1],"car%d.png"%(idx+1),initPos[1][idx],None])
            if idx<len(driverNameList):
                driverNameDict[row[-1]]=driverNameList[idx]
        if not isDriver:
            result = self.db.fetchall("user",None)
            passengerList=[]
            passengerIdx = 0
            for idx,row in enumerate(result):
                if not row[0] in driverList:
                    passengerList.append([row[0],"passenger%d.png"%(passengerIdx+1),initPos[0][passengerIdx],endPos[0][passengerIdx]])
                    if passengerIdx<len(passengerNameList):
                        passengerNameDict[row[0]]=passengerNameList[passengerIdx]
                    passengerIdx += 1
            return passengerList
        else:
            return driverList

    def addOneTaxi(self,params,peer=None):
        idx = len(self.taxiList)
        if idx>=len(self.driverList):
            log1.error("only %d taxi are supported in this game"%len(self.driverList))
            return
        if peer:
            phone = peer.phoneNum
        else:
            phone = self.driverList[idx][0]
        imgname=self.driverList[idx][1]
        initPos = self.driverList[idx][2]
        endPos  = self.driverList[idx][3]


        taxi = Taxi(phone,self,imgname,initPos,endPos)
        if not peer:
            peer = driver.Driver(taxi)
        taxi.peer = peer
        peer.enableUDSTask()
        self.addList.append(taxi)
        self.taxiList.append(taxi)
        taxi.login()
        return taxi
    def addOnePerson(self,params,peer=None):
        idx = len(self.personList)
        if idx>=len(self.passengerList):
            log1.error("only %d passengers are supported in this game"%len(self.passengerList))
            return None
        if peer:
            phone = peer.phoneNum
        else:
            phone = self.passengerList[idx][0]
      
        imgname = self.passengerList[idx][1]
        initPos = self.passengerList[idx][2]
        endPos  = self.passengerList[idx][3]
        
        person = Person(phone,self,imgname,initPos,endPos)
        if not peer:
            peer = passenger.Passenger(person)
        person.peer = peer

        self.addList.append(person)
        self.personList.append(person)

        person.login()
        return person
    def getPeerByID(self,id):
        for person in self.personList:
            if person.phone==id:
                return person
            
        for driver in self.taxiList:
            if driver.phone==id:
                return driver    
    def addOneSprite(self,sprite):
        if sprite not in self.sprites:
            self.addList.append(sprite)

    def deleteOneSprite(self,sprite):
        if sprite in self.sprites:
             self.deleteList.append(sprite)

    def _deleteFromGroup(self,sprite):
        if sprite in self.sprites:#in theory it is redundant check, but it happens anyway
            sprite.remove((self.mainSprites))
            self.sprites.remove(sprite)
            log1.debug("remove sprite%s"%sprite.name)

    def _addToGroup(self,sprite):

        if sprite not in self.sprites:#in theory it is redundant check, but it happens anyway
            sprite.add((self.mainSprites))
            self.sprites.insert(0,sprite)
            log1.debug("add sprite%s"%sprite.name)

    def update(self):
        #add /delete sprite
        len1 = len(self.addList)
        while len1:
            len1 -= 1
            item = self.addList.pop()
            self._addToGroup(item)

        len1 = len(self.deleteList)
        while len1:
            len1 -= 1
            item = self.deleteList.pop()
            self._deleteFromGroup(item)

    def _removePopUpMenu(self):
        for sprite in self.sprites:
            if isinstance(sprite,gameEngine.PopupMenu):
                self.deleteOneSprite(sprite)
            if isinstance(sprite,Entity) and sprite.showStatus:
                sprite.showStatus = False

    def OnClick(self,event):

        buttons = pygame.mouse.get_pressed()
        if buttons[2] == 1:
                self.addOneSprite(self.addPeerMenu)
        elif buttons[0] == 1:
                self._removePopUpMenu()
    def exit(self):
        for taxi in self.taxiList:
            taxi.exit()
        for person in self.personList:
            person.exit()
        pygame.quit()
def test():
     paramDict={CSTR3_REPORTER:2,CSTR2_SERVICE:3,CSTR3_RESULT:4}
     my_event = pygame.event.Event(EVT_WAITCONFIRM[0], paramDict)
     print my_event.type,  my_event.reporter, my_event.service, my_event.result

gameActivity = None
def Run(flag):
    #import pycallgraph
    #pycallgraph.start_trace()
    global globalFlag
    global FilterRequestList
    globalFlag = flag
    if(flag&NOTIFY_ALL):
        #FilterRequestList=[]
        NotifyMenuList=[]
    try:
        if (flag&RUN_SERVER):
            import iNeedCenter
            server = iNeedCenter.MsgCenter(centerAddr)
        global gameActivity
        gameActivity = IneedMap((MAP_WIDTH,MAP_HEIGHT),os.path.join(IMGPath,"map1.jpg"))
        
        gameActivity.start()
    except:
        pygame.quit()
        log1.exception("exit\n")
    if (flag&RUN_SERVER):
        server.exit()
    #pycallgraph.stop_trace()
    #pycallgraph.make_dot_graph('E:\kingCloud\ineed-taxi\code\doc\game.png')

if __name__=="__main__":
    
    import cProfile
    outProfileName="E:\kingCloud\ineed-taxi\code\doc\game.profile"
    #lat,logt = getLocation2(640,320)[:2]
    #print reverseGetLocation(lat,logt)
    import configall
    configall.SHORTTIME_LIMIT = 15
    configall.TIMEZONE        = 150
    configall.GAMETEST        = True
    AUTOEXE = True
    if False:
        cProfile.run('Run()', outProfileName)
    else:
        Run(RUN_SERVER)

